// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

// Private header, not to be exported

#pragma once

#include <utility>

#include <nebula/types/scalar.h>
#include <turbo/utility/status.h>
#include <nebula/types/type.h>
#include <nebula/core/visitor_generate.h>

namespace nebula {

#define SCALAR_VISIT_INLINE(TYPE_CLASS)                                              \
      case TYPE_CLASS##Type::type_id:                                                    \
        return visitor->Visit(turbo::checked_cast<const TYPE_CLASS##Scalar&>(scalar), \
                              std::forward<ARGS>(args)...);

    /// \brief Apply the visitors Visit() method specialized to the scalar type
    ///
    /// \tparam VISITOR Visitor type that implements Visit() for all scalar types.
    /// \tparam ARGS Additional arguments, if any, will be passed to the Visit function after
    /// the `scalar` argument
    /// \return turbo::Status
    ///
    /// A visitor is a type that implements specialized logic for each Nebula type.
    /// Example usage:
    ///
    /// ```
    /// class ExampleVisitor {
    ///   turbo::Status Visit(nebula::Int32Scalar scalar) { ... }
    ///   turbo::Status Visit(nebula::Int64Scalar scalar) { ... }
    ///   ...
    /// }
    /// ExampleVisitor visitor;
    /// visit_scalar_inline(some_scalar, &visitor);
    /// ```
    template<typename VISITOR, typename... ARGS>
    inline turbo::Status visit_scalar_inline(const Scalar &scalar, VISITOR *visitor, ARGS &&... args) {
        switch (scalar.type->id()) {
            NEBULA_GENERATE_FOR_ALL_TYPES(SCALAR_VISIT_INLINE);
            default:
                break;
        }
        return turbo::unimplemented_error("Scalar visitor for type not implemented ",
                                             scalar.type->to_string());
    }

#undef SCALAR_VISIT_INLINE

}  // namespace nebula
